#define __MULTI_THREAD__

#define TRUE 'T'
#define FALSE 'F'

#define HTTP_TIMEOUT 60
#define BACKLOG 5
#define MAX_HEADER_SIZE 5000
#define MAX_TOKEN_SIZE 5000
#define MAX_ADDR_SIZE 4000
#define TIME_LENGTH 80

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// #include <time.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>


pthread_mutexattr_t server_mutex; 


struct struct_request_header {
	char host[MAX_ADDR_SIZE];			// e.g. cse.cuhk.edu.hk:81
	char relative_path[MAX_ADDR_SIZE];	// e.g. /index.html
	char connection_type[15];			// e.g. HTTP/1.1
	char ims_time_string[80];
	time_t ims_time;
	char is_ims;						// TRUE or FALSE
	char is_cache_control;				// TRUE or FALSE
	char is_get;						// TRUE if GET request, otherwise FALSE (e.g. POST)
	char is_interested_type;			// e.g. html, jpg, fig, txt
	short port;							// e.g. 80
	char is_keep_alive;
};

struct struct_response_header {
	short status_code;
	time_t ims_time;
	char is_fix_length;
	char is_no_centent;
	char is_keep_alive;
	char ims_time_string[80];
	char encoding[20];					// e.g. gzip	
	unsigned int content_length;
};

struct struct_request_identity {
	int server_socket_descriptor;
	int client_socket_descriptor;
	char file_name[28];
	//char* file_name;
	char ims_time_string[80];
	time_t ims_time;
	char is_ims;						// TRUE or FALSE
	char is_cache_control;				// TRUE or FALSE
	char connection_type[15];			// e.g. HTTP/1.1
	char is_ims_modified;				// TRUE or FALSE
	char encoding[20];					// e.g. gzip
	char is_interested_type;			// e.g. html, jpg, fig, txt
};

/* myproxy.c */
char* generate_filename(char* req_host, char* req_relative_path, short port);
char *crypt(const char *key, const char *salt);
int not_modified_since(char* cache_time, char* req_time);
char *strptime(const char *s, const char *format, struct tm *tm);

char* to_time_string(time_t *time_input, char *time_string);
time_t to_time_t(char* time_string);
time_t find_cache_last_modified_time(char* path);

/* send_request.c */
int forward_request(int client_socket_descriptor, char* req_header_raw, struct struct_request_header *requestHeader);
int forward_exact_request(int client_socket_descriptor, char* req_header_raw, struct struct_request_header *requestHeader);

/* send_response.c */
char is_cached(char* file_name);
void forward_response(char* response_header_raw, struct struct_response_header *responseHeader, struct struct_request_identity *requestIdentity);
void case1_2b_request_process(struct struct_request_identity *requestIdentity);
void case2a_request_process(struct struct_request_identity *requestIdentity);
char case1_response_process(char* response_header_raw, struct struct_response_header *responseHeader, struct struct_request_identity *requestIdentity, char need_cache);

/* process_request.c */
void receive_and_process_request_thread(int client_socket_descriptor);
int case3_request_process(int client_socket_descriptor, char* req_header_raw, struct struct_request_header *requestHeader, struct struct_request_identity *requestIdentity);
int case4a_request_process(int client_socket_descriptor, char* req_header_raw, struct struct_request_header *requestHeader, struct struct_request_identity *requestIdentity);

/* process_response.c */
int receive_and_process_response_thread(struct struct_request_identity *requestIdentity);

/* messaging.c */
int recvn(int socket_descriptor, void* buf, int buf_len);
int sendn(int socket_descriptor, const void* buf, int buf_len);




/* Shared object (Need mutex protect) */
char is_cached(char* file_name);
int cache_response(char* file_name, char* data, int data_length, char* write_mode);